package com.cs.service.impl;

import com.cs.config.RabbitMqConfig;
import com.cs.domain.*;
import com.cs.domain.vo.*;
import com.cs.mapper.CSProcurementPlanMapper;
import com.cs.mapper.CsTenderMapper;
import com.cs.service.CSProcurementPlanService;
import com.cs.service.ICsTenderService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.rabbitmq.client.Channel;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.utils.DateUtils;
import com.ruoyi.common.core.utils.ip.IpUtils;
import com.ruoyi.common.security.utils.SecurityUtils;
import com.ruoyi.system.api.model.LoginUser;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

/**
 * 招标项目Service业务层处理
 *
 * @author ruoyi
 * @date 2024-11-25
 */
@Service
public class CsTenderServiceImpl implements ICsTenderService {

    private static final int MAX_RETRIES = 3;
    @Autowired
    private CsTenderMapper csTenderMapper;
    @Autowired
    private CSProcurementPlanMapper csProcurementPlanMapper;
    @Autowired
    private CSProcurementPlanService csProcurementPlanService;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private ObjectMapper objectMapper;
    private Map<String, Integer> retryCountMap = new HashMap<>();

    /**
     * 查询招标项目
     *
     * @param sId 招标项目主键
     * @return 招标项目
     */
    @Override
    public CsTender selectCsTenderBySId(Long sId) {
        return csTenderMapper.selectCsTenderBySId(sId);
    }

    /**
     * 查询招标项目列表
     *
     * @param csTender 招标项目
     * @return 招标项目
     */
    @Override
    public List<CsTender> selectCsTenderList(CsTender csTender) {
        return csTenderMapper.selectCsTenderList(csTender);
    }

    /**
     * 新增招标项目
     *
     * @param csTender 招标项目
     * @return 结果
     */
    @Override
    public int insertCsTender(TenderInviteSupplierVO csTender) {
        CsTender tender = csTender.getTender();
        if (csTender.getTenderList() != null) {
            //新增邀请招标商
            csTenderMapper.inserInviteSupplier(csTender.getTenderList());
        }
        tender.setCreateTime(DateUtils.getNowDate());
        return csTenderMapper.insertCsTender(tender);
    }

    /**
     * 修改招标项目
     *
     * @param csTender 招标项目
     * @return 结果
     */
    @Override
    public int updateCsTender(CsTender csTender) {
        csTender.setUpdateTime(DateUtils.getNowDate());
        return csTenderMapper.updateCsTender(csTender);
    }

    /**
     * 批量删除招标项目
     *
     * @param sIds 需要删除的招标项目主键
     * @return 结果
     */
    @Override
    public int deleteCsTenderBySIds(Long[] sIds) {
        return csTenderMapper.deleteCsTenderBySIds(sIds);
    }

    /**
     * 删除招标项目信息
     *
     * @param sId 招标项目主键
     * @return 结果
     */
    @Override
    public int deleteCsTenderBySId(Long sId) {
        return csTenderMapper.deleteCsTenderBySId(sId);
    }

    @Override
    public Map<String, Object> getTenderProjectInfo(String iNumber) {
        TenderNoticeVO projectStateAndStartTime = null;
        List<TenderNeedLineItemsVO> list = null;
        CsTender csTender = csTenderMapper.getTender(iNumber);
        String xyId = csTender.getXyId();

        CompletableFuture<TenderNoticeVO> tenderNoticeVOCompletableFuture =
                CompletableFuture.supplyAsync(() -> csTenderMapper.getProjectStateAndStartTime(iNumber));

        CompletableFuture<List<TenderNeedLineItemsVO>> listCompletableFuture =
                CompletableFuture.supplyAsync(() -> csProcurementPlanService.getTenderNeedLineItems(xyId));

        List<File> file = csTenderMapper.getTenderProjectInfo(iNumber);
        List<CsSupplier> suppliers = csTenderMapper.getSupplierByINumber(iNumber);

        try {
            projectStateAndStartTime = tenderNoticeVOCompletableFuture.get();
            list = listCompletableFuture.get();
        } catch (InterruptedException | ExecutionException e) {
            throw new RuntimeException(e);
        }

        Map<String, Object> map = new HashMap<>();
        map.put("tenderProjectInfo", csTender);
        map.put("notice", projectStateAndStartTime);
        map.put("purchasePlan", list);
        map.put("file", file);
        map.put("suppliers", suppliers);
        return map;
    }

    @Override
    public R<Integer> updateTenderProject(TenderFileVO csTender) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        csTender.getCsTender().setUpdateBy(loginUser.getUsername());
        csTender.getCsTender().setUpdateTime(new Date());
        Integer res = csTenderMapper.updateCsTender(csTender.getCsTender());
        csProcurementPlanMapper.deleteFileByINumber(csTender.getCsTender().getiNumber());
        if (res > 0) {
            CompletableFuture.runAsync(() -> {
                List<CSPubAttachments> collect1 = csTender.getFile().stream().map(s -> {
                    CSPubAttachments csPubAttachments = new CSPubAttachments();
                    csPubAttachments.setiNumber(csTender.getCsTender().getiNumber());
                    csPubAttachments.setCreateBy(loginUser.getUsername());
                    csPubAttachments.setUpdateBy(loginUser.getUsername());
                    csPubAttachments.setAnSize(s.getSize());
                    csPubAttachments.setAnName(s.getName());
                    csPubAttachments.setAnUrl(s.getUrl());
                    return csPubAttachments;
                }).toList();
                csProcurementPlanMapper.addPubFileByINumber(collect1);
            });
            return R.ok(1, "success");
        }
        return R.fail("fail");
    }

    @Override
    @Transactional
    public R<Integer> deleteTenderProject(String iNumber) {
        //先获得采购计划编码
        String aCode = csTenderMapper.getACode(iNumber);
        //删除招标项目前判断状态(sql执行)
        csTenderMapper.deleteCsTender(iNumber);
        //异步更新采购计划状态3
        updatePlanStateAsync(aCode);
        //删除文件
        Integer integer = csProcurementPlanMapper.deleteFileByINumber(iNumber);
        if (integer > 0) {
            return R.ok(1, "删除成功");
        }
        return R.fail("删除失败");
    }

    @Async
    @Transactional
    public void updatePlanStateAsync(String aCode) {
        CSProcurementPlanVO planVO = new CSProcurementPlanVO();
        planVO.setAstate(3);
        planVO.setaCode(aCode);
        csProcurementPlanMapper.updatePlanStateByACode(planVO);
    }

    @Override
    public R<Integer> changeTenderProjectStatus(TenderFileVO csTender) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        csTender.getCsTender().setUpdateBy(loginUser.getUsername());
        csTender.getCsTender().setUpdateTime(new Date());
        csTender.getCsTender().setProjectState(Long.parseLong(2 + ""));
        if (csTender.getCsTender().getiWay() == 6) {
            //新增邀请招标商
            csTender.getInviteTenders().forEach(s -> {
                s.setCreateTime(new Date());
                s.setCreateBy(loginUser.getUsername());
                s.setiNumber(csTender.getCsTender().getiNumber());
            });
            csTenderMapper.inserInviteSupplier(csTender.getInviteTenders());
        }
        Integer res = csTenderMapper.updateCsTender(csTender.getCsTender());
        csProcurementPlanMapper.deleteFileByINumber(csTender.getCsTender().getiNumber());
        if (res > 0) {
            CompletableFuture.runAsync(() -> {
                List<CSPubAttachments> collect1 = csTender.getFile().stream().map(s -> {
                    CSPubAttachments csPubAttachments = new CSPubAttachments();
                    csPubAttachments.setiNumber(csTender.getCsTender().getiNumber());
                    csPubAttachments.setCreateBy(loginUser.getUsername());
                    csPubAttachments.setUpdateBy(loginUser.getUsername());
                    csPubAttachments.setAnSize(s.getSize());
                    csPubAttachments.setAnName(s.getName());
                    csPubAttachments.setAnUrl(s.getUrl());
                    return csPubAttachments;
                }).toList();
                csProcurementPlanMapper.addPubFileByINumber(collect1);
            });
            return R.ok(1, "success");
        }
        return R.fail("fail");
    }

    @Override
    public List<CSNotice> getTenderNoticeByINumber(String iNumber) {
        return csTenderMapper.getTenderNoticeByINumber(iNumber);
    }

    @Override
    public R<Integer> addTenderNotice(NoticeVO noticeVO) {
        CSNotice csNotice = new CSNotice();
        String[] acceptTime = noticeVO.getAcceptTime();
        String[] kaiTime = noticeVO.getKaiTime();
        String[] getTime = noticeVO.getGetTime();
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        if (acceptTime != null && acceptTime.length > 0) {
            try {
                //答疑时间
                csNotice.setAcceptTime(formatter.parse(acceptTime[0]));
                csNotice.setAcceptEndTime(formatter.parse(acceptTime[1]));

                //获得标书时间
                csNotice.setGetStartTime(formatter.parse(getTime[0]));
                csNotice.setGetEndTime(formatter.parse(getTime[1]));

                //开标时间
                csNotice.setKaiStartTime(formatter.parse(kaiTime[0]));
                csNotice.setKaiEndTime(formatter.parse(kaiTime[1]));
            } catch (ParseException e) {
                throw new RuntimeException(e);
            }
        }

        csNotice.setiNumber(noticeVO.getiNumber());
        csNotice.setTitle(noticeVO.getTitle());
        csNotice.setProject(noticeVO.getProject());
        csNotice.setMoney(noticeVO.getMoney());
        csNotice.setStatus(1);
        csNotice.setnType(noticeVO.getnType());
        csNotice.setRemark(noticeVO.getRemark());
        Integer uId = csTenderMapper.addTenderNotice(csNotice);//已返回uId(使用对象.uId)
        if (uId > 0) {
            addNoticeFile(noticeVO.getFileList(), csNotice.getuId(), csNotice.getiNumber());
            return R.ok(1, "success");
        }
        return R.fail("fail");
    }

    @Override
    public NoticeVO getNoticeInfoByUId(String uId) {
        CSNotice csNotices = csTenderMapper.getNoticeInfoByUId(uId);
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        CompletableFuture<NoticeVO> noticeVOCompletableFuture = CompletableFuture.supplyAsync(() -> {
            NoticeVO noticeVO = new NoticeVO();
            String[] accept = new String[2];
            String[] kai = new String[2];
            String[] get = new String[2];
            if (csNotices.getAcceptTime() != null) {
                //如果一个为空,那么其它必定为空
                accept[0] = formatter.format(csNotices.getAcceptTime());
                accept[1] = formatter.format(csNotices.getAcceptEndTime());

                kai[0] = formatter.format(csNotices.getKaiStartTime());
                kai[1] = formatter.format(csNotices.getKaiEndTime());

                get[0] = formatter.format(csNotices.getGetStartTime());
                get[1] = formatter.format(csNotices.getGetEndTime());
            }


            noticeVO.setAcceptTime(accept);
            noticeVO.setGetTime(get);
            noticeVO.setKaiTime(kai);
            noticeVO.setProject(csNotices.getProject());
            noticeVO.setTitle(csNotices.getTitle());
            noticeVO.setMoney(csNotices.getMoney());
            noticeVO.setRemark(csNotices.getRemark());
            noticeVO.setuId(csNotices.getuId());
            noticeVO.setiNumber(csNotices.getiNumber());
            noticeVO.setStatus(csNotices.getStatus());
            noticeVO.setnType(csNotices.getnType());
            return noticeVO;
        });
        List<CSPubAttachments> attachments = csProcurementPlanMapper.getNoticeFile(uId);
        List<File> files = attachments.stream().map(s -> {
            File file = new File();
            file.setName(s.getAnName());
            file.setUrl(s.getAnUrl());
            file.setSize(s.getAnSize());
            return file;
        }).toList();
        NoticeVO noticeVO1 = null;
        try {
            noticeVO1 = noticeVOCompletableFuture.get();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }
        noticeVO1.setFileList(files);
        return noticeVO1;
    }

    public void addNoticeFile(List<File> files, Integer uId, String iNumber) {
        System.out.println("Inumber"+iNumber);
        CompletableFuture.runAsync(() -> {
            List<CSPubAttachments> csPubAttachments1 = files.stream().map(s -> {
                CSPubAttachments csPubAttachments = new CSPubAttachments();
                csPubAttachments.setAnName(s.getName());
                csPubAttachments.setAnUrl(s.getUrl());
                csPubAttachments.setAnSize(s.getSize());
                csPubAttachments.setAnUploadTime(new Date());
                csPubAttachments.setuId(uId);
                csPubAttachments.setiNumber(iNumber);
                return csPubAttachments;
            }).toList();
            if (csPubAttachments1.size() > 0) {
                csProcurementPlanService.addNoticeFile(csPubAttachments1);
            }
        });
    }

    public void addNoticeFile(List<File> files, Integer uId) {
        CompletableFuture.runAsync(() -> {
            List<CSPubAttachments> csPubAttachments1 = files.stream().map(s -> {
                CSPubAttachments csPubAttachments = new CSPubAttachments();
                csPubAttachments.setAnName(s.getName());
                csPubAttachments.setAnUrl(s.getUrl());
                csPubAttachments.setAnSize(s.getSize());
                csPubAttachments.setAnUploadTime(new Date());
                csPubAttachments.setuId(uId);
                return csPubAttachments;
            }).toList();
            if (csPubAttachments1.size() > 0) {
                csProcurementPlanService.addNoticeFile(csPubAttachments1);
            }

        });
    }

    @Override
    public R<Integer> submitTenderNotice(NoticeVO noticeVO) {
        csTenderMapper.deleteNoticePubattachments(noticeVO.getuId());
        addNoticeFile(noticeVO.getFileList(), noticeVO.getuId());

        CSNotice csNotice = new CSNotice();
        String[] acceptTime = noticeVO.getAcceptTime();
        String[] kaiTime = noticeVO.getKaiTime();
        String[] getTime = noticeVO.getGetTime();
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        if (acceptTime != null && acceptTime[0] != null && acceptTime[1] != null) {
            try {
                //答疑时间
                csNotice.setAcceptTime(formatter.parse(acceptTime[0]));
                csNotice.setAcceptEndTime(formatter.parse(acceptTime[1]));

                //获得标书时间
                csNotice.setGetStartTime(formatter.parse(getTime[0]));
                csNotice.setGetEndTime(formatter.parse(getTime[1]));

                //开标时间
                csNotice.setKaiStartTime(formatter.parse(kaiTime[0]));
                csNotice.setKaiEndTime(formatter.parse(kaiTime[1]));
            } catch (ParseException e) {
                throw new RuntimeException(e);
            }
        }

        csNotice.setiNumber(noticeVO.getiNumber());
        csNotice.setTitle(noticeVO.getTitle());
        csNotice.setProject(noticeVO.getProject());
        csNotice.setMoney(noticeVO.getMoney());
        csNotice.setRemark(noticeVO.getRemark());
        csNotice.setStatus(2);
        csNotice.setuId(noticeVO.getuId());

        Integer result = csTenderMapper.updateNoticeByUid(csNotice);
        if (result > 0) {
            return R.ok(1, "success");
        }
        return R.fail("error");
    }

    @Override
    public R<Integer> editTenderNotice(NoticeVO noticeVO) {
        csTenderMapper.deleteNoticePubattachments(noticeVO.getuId());
        addNoticeFile(noticeVO.getFileList(), noticeVO.getuId());

        CSNotice csNotice = new CSNotice();
        String[] acceptTime = noticeVO.getAcceptTime();
        String[] kaiTime = noticeVO.getKaiTime();
        String[] getTime = noticeVO.getGetTime();
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            //答疑时间
            csNotice.setAcceptTime(formatter.parse(acceptTime[0]));
            csNotice.setAcceptEndTime(formatter.parse(acceptTime[1]));

            //获得标书时间
            csNotice.setGetStartTime(formatter.parse(getTime[0]));
            csNotice.setGetEndTime(formatter.parse(getTime[1]));

            //开标时间
            csNotice.setKaiStartTime(formatter.parse(kaiTime[0]));
            csNotice.setKaiEndTime(formatter.parse(kaiTime[1]));
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
        csNotice.setiNumber(noticeVO.getiNumber());
        csNotice.setTitle(noticeVO.getTitle());
        csNotice.setProject(noticeVO.getProject());
        csNotice.setMoney(noticeVO.getMoney());
        csNotice.setRemark(noticeVO.getRemark());
        csNotice.setuId(noticeVO.getuId());
        csNotice.setnType(noticeVO.getnType());

        Integer result = csTenderMapper.updateNoticeByUid(csNotice);
        if (result > 0) {
            return R.ok(1, "success");
        }
        return R.fail("error");
    }

    @Override
    public R<Integer> examineNoticeRow(NoticeVO noticeVO) {
        CSNotice csNotice = new CSNotice();
        csNotice.setRemark(noticeVO.getRemark());
        csNotice.setStatus(3);
        csNotice.setuId(noticeVO.getuId());
        Integer integer = csTenderMapper.updateNoticeByUid(csNotice);
        if (integer > 0) {
            return R.ok(1, "success");
        }
        return R.fail("fail");
    }

    @Override
//    @Transactional
    public R<Integer> releaseNoticeRow(String uId) {
        CSNotice noticeInfoByUId = csTenderMapper.getNoticeInfoByUId(uId);
        CSNotice csNotice = new CSNotice();
        csNotice.setuId(Integer.parseInt(uId));
        csNotice.setStatus(5);
        String s = noticeInfoByUId.getiNumber();
        csTenderMapper.deleteNoticeRowByINumberStatus(s);

        //消息发送
        if (noticeInfoByUId.getnType() == 1) {
            Date now = new Date();
            //先投标中再变成开标
            Date getStartTime = noticeInfoByUId.getGetStartTime();
            long l = getStartTime.getTime() - now.getTime();

            //设置开标时间,如果公告覆盖更改,在消息接收中判断iNumber和uId是否一致,不一致不消费
            Date endTime = noticeInfoByUId.getGetEndTime();
            String s2 = null;
            try {
                s2 = objectMapper.writeValueAsString(noticeInfoByUId);
            } catch (JsonProcessingException e) {
                throw new RuntimeException(e);
            }
            Random rando = new Random();
            int fourDigitRandomNumber = rando.nextInt(9000) + 1000;
            CorrelationData correlationData = new CorrelationData("12312" + fourDigitRandomNumber);
            if (l > 0) {
                System.out.println("发送消息" + l);
                // 发送带有延迟的消息
                rabbitTemplate.convertAndSend(RabbitMqConfig.BINDING_BINDING_EXCHANGE, RabbitMqConfig.BINDING_BINDING_ROUTE, s2, msg -> {
                    msg.getMessageProperties().setHeader("x-delay", l);
                    msg.getMessageProperties().setContentType(MessageProperties.CONTENT_TYPE_JSON);
                    msg.getMessageProperties().setMessageId("12312" + fourDigitRandomNumber);
                    return msg;
                }, correlationData);
            } else {
                // 如果延迟时间为负值，直接发送消息
                System.out.println("直接发送消息");
                rabbitTemplate.convertAndSend(RabbitMqConfig.BINDING_BINDING_EXCHANGE, RabbitMqConfig.BINDING_BINDING_ROUTE, s2, msg -> {
                    msg.getMessageProperties().setContentType(MessageProperties.CONTENT_TYPE_JSON);
                    msg.getMessageProperties().setMessageId("12312" + fourDigitRandomNumber);
                    return msg;
                }, correlationData);
            }
            // 计算延迟时间（以毫秒为单位）
            long delayInMilliseconds = endTime.getTime() - now.getTime();
            String s1 = null;
            try {
                s1 = objectMapper.writeValueAsString(noticeInfoByUId);
            } catch (JsonProcessingException e) {
                throw new RuntimeException(e);
            }
            int qqw = rando.nextInt(9000) + 1000;
            CorrelationData correlationData2 = new CorrelationData("12312" + qqw);
            if (delayInMilliseconds > 0) {
                // 发送带有延迟的消息
                System.out.println("发送消息2ww" + delayInMilliseconds);
                rabbitTemplate.convertAndSend(RabbitMqConfig.OPEN_BINDING_EXCHANGE, RabbitMqConfig.OPEN_BINDING_ROUTE, s1, msg -> {
                    msg.getMessageProperties().setHeader("x-delay", delayInMilliseconds);
                    msg.getMessageProperties().setContentType(MessageProperties.CONTENT_TYPE_JSON);
                    msg.getMessageProperties().setMessageId("12312" + qqw);
                    return msg;
                }, correlationData2);
            } else {
                System.out.println("直接发送消息2");
                // 如果延迟时间为负值，直接发送消息
                rabbitTemplate.convertAndSend(RabbitMqConfig.OPEN_BINDING_EXCHANGE, RabbitMqConfig.OPEN_BINDING_ROUTE, s1, msg -> {
                    msg.getMessageProperties().setContentType(MessageProperties.CONTENT_TYPE_JSON);
                    msg.getMessageProperties().setMessageId("12312" + qqw);
                    return msg;
                }, correlationData2);
            }
        }
        Integer integer = csTenderMapper.updateNoticeByUid(csNotice);
        if (integer > 0) {
            return R.ok(1, "success");
        }
        return R.fail("fail");
    }

    @Override
    public R<Integer> deleteNoticeRow(String uId) {
        Integer integer = csTenderMapper.deleteNoticeRow(Integer.parseInt((uId)));
        if (integer > 0) {
            csTenderMapper.deleteNoticePubattachments(Integer.parseInt((uId)));
        }
        return R.ok(1, "success");
    }

    @Override
    public List<File> getFileListByINumber(String iNumber) {
        List<CSPubAttachments> csPubAttachments = csTenderMapper.getPubAttachmentsList(iNumber);
        return csPubAttachments.stream()
                .map(s -> {
                    File file = new File();
                    file.setbDocuId(s.getbDocuId());
                    file.setSize(s.getAnSize());
                    file.setName(s.getAnName());
                    file.setUrl(s.getAnUrl());
                    file.setUploadTime(s.getAnUploadTime());
                    return file;
                }).toList();
    }

    @Override
    public R<Integer> rejectNotice(Integer uId) {
        CSNotice csNotice = new CSNotice();
        csNotice.setStatus(4);
        csNotice.setuId(uId);
        Integer integer = csTenderMapper.updateNoticeByUid(csNotice);
        if (integer > 0) {
            return R.ok(1, "success");
        }
        return R.fail("fail");
    }

    @Override
    public R<Integer> addTenderFile(TenderFileNameVO fileNameVO) {
        File file = fileNameVO.getFile().get(0);
        CSPubAttachments csPubAttachments = new CSPubAttachments();
        csPubAttachments.setiNumber(fileNameVO.getiNumber());
        csPubAttachments.setAnName(fileNameVO.getName());
        csPubAttachments.setAnSize(file.getSize());
        csPubAttachments.setAnUrl(file.getUrl());
        Random random = new Random();
        int randomNumber = random.nextInt(999999) + 1;
        csPubAttachments.setbDocuId(randomNumber);
        Integer integer = csProcurementPlanMapper.addTenderFile(csPubAttachments);
        if (integer > 0) {
            return R.ok(1, "success");
        }
        return R.fail("fail");
    }

    @Override
    public R<Integer> deleteTenderFile(Integer bDocuId) {
        Integer integer = csTenderMapper.deleteTenderFile(bDocuId);
        if (integer > 0) {
            return R.ok(1, "success");
        }
        return R.fail("fail");
    }

    @Override
    public R<Map<String, Object>> bidGetDocumentPeople(String iNumber) {
        TenderDocumentVO tenderDocumentVO = csTenderMapper.getBidDocumentEndTime(iNumber);
        List<TenderGetInfoVO> list = csTenderMapper.getBidPeople(iNumber);
        Map<String, Object> map = new HashMap<>();
        map.put("tender", tenderDocumentVO);
        map.put("tenderPeople", list);
        return R.ok(map);
    }

    @Override
    public R<List<SubmissionSupplierVO>> getBidPeopleList(String iNumber) {
        List<SubmissionSupplierVO> list = csTenderMapper.getBidPeopleList(iNumber);
        System.out.println("list.size() = " + list.size());
        return R.ok(list);
    }

    @Override
    public R<CsTender> getTender(String iNumber) {
        CsTender tender = csTenderMapper.getTender(iNumber);
        return R.ok(tender);
    }

    @RabbitListener(queues = RabbitMqConfig.BINDING_BINDING_QUEUE)
    public void bindingStart(CSNotice csNotice, Message message, Channel channel) {
        System.out.println("确定公告 = " + csNotice);
        String messageId = message.getMessageProperties().getMessageId();
        System.out.println("messageId = " + messageId);
        int retryCount = retryCountMap.getOrDefault(messageId, 0);
        if (retryCount >= MAX_RETRIES) {
            System.out.println("消息 " + messageId + " 达到最大重试次数 " + MAX_RETRIES + " 次，拒绝消息。");
            try {
                channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
            } catch (Exception e) {
                System.out.println("消息拒绝失败: " + e);
            }
            return;
        }
        retryCount++;
        retryCountMap.put(messageId, retryCount);
        try {
            // 查询是否招标类型的公告是否覆盖了原本的公告
            Integer count = csTenderMapper.isExitNotice(csNotice.getuId());
            if (count == 1) {
                CsTender tender = new CsTender();
                tender.setiNumber(csNotice.getiNumber());
                tender.setProjectState(3L);
                int i = csTenderMapper.changeStaus(tender);
                System.out.println("i = " + i);
                // 手动确认消息
                channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
            } else {
                // 如果覆盖，直接拒绝消息
                channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
            }
        } catch (Exception e) {
            // 处理异常，可以选择重新入队或拒绝消息
            System.out.println("e = " + e);
            try {
                if (retryCount < MAX_RETRIES) {
                    // 重试次数未达到最大值，重新入队
                    channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
                } else {
                    // 达到最大重试次数，拒绝消息
                    channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
                }
            } catch (IOException ex) {
                throw new RuntimeException(ex);
            }
        }
    }

    @RabbitListener(queues = RabbitMqConfig.OPEN_BINDING_QUEUE)
    public void kaiTimeAccept(CSNotice csNotice, Message message, Channel channel) {
        String messageId = message.getMessageProperties().getMessageId();
        int retryCount = retryCountMap.getOrDefault(messageId, 0);
        if (retryCount >= MAX_RETRIES) {
            System.out.println("消息 " + messageId + " 达到最大重试次数 " + MAX_RETRIES + " 次，拒绝消息。");
            try {
                channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
            } catch (Exception e) {
                System.out.println("消息拒绝失败: " + e);
            }
            return;
        }
        retryCount++;
        retryCountMap.put(messageId, retryCount);
        try {
            // 查询是否招标类型的公告是否覆盖了原本的公告
            Integer count = csTenderMapper.isExitNotice(csNotice.getuId());
            if (count == 1) {
                // 没有覆盖, 消费
                // 1. 获得投标供应商的数量
                List<CSSubmission> submissions = csTenderMapper.getSupplierSubmitBinding(csNotice.getiNumber());
                CsTender tender = new CsTender();
                tender.setiNumber(csNotice.getiNumber());
                if (submissions.size() < 3) {
                    // 将项目状态改成废标
                    tender.setProjectState(7L);
                } else {
                    // 将项目状态改成开标中
                    tender.setProjectState(4L);
                }
                int i = csTenderMapper.changeStaus(tender);
                System.out.println("i = " + i);
                // 手动确认消息
                channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
            } else {
                // 如果覆盖，直接拒绝消息
                channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
            }
        } catch (Exception e) {
            // 处理异常，可以选择重新入队或拒绝消息
            System.out.println("e = " + e);
            try {
                if (retryCount < MAX_RETRIES) {
                    // 重试次数未达到最大值，重新入队
                    channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
                } else {
                    // 达到最大重试次数，拒绝消息
                    channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
                }
            } catch (IOException ex) {
                throw new RuntimeException(ex);
            }
        }

    }

    @Override
    public R<TenderNoticeVO> getProjectStateAndStartTime(String iNumber) {
        TenderNoticeVO noticeVO = csTenderMapper.getProjectStateAndStartTime(iNumber);
        return R.ok(noticeVO);
    }

    @Override
    public List<CsCandidate> getAllSupplierList(CsTender tender) {
        return csTenderMapper.getAllSupplierList(tender);
    }

    @Override
    public List<CsSupplier> getAllBidder(String iNumber) {
        return csTenderMapper.getAllBidder(iNumber);
    }

    @Override
    public Integer addCandidate(CsCandidate csCandidate) {
        // 1. 插入新记录
        csTenderMapper.addCandidate(csCandidate);

        // 2. 获取所有相关记录
        CsTender csTender = new CsTender();
        csTender.setiNumber(csCandidate.getiNumber());
        List<CsCandidate> csConditions = csTenderMapper.getAllSupplierList(csTender);

        // 3. 重新计算排名或其它属性
        csConditions = recalculateRanking(csConditions);

        // 4. 更新数据库
        for (CsCandidate candidate : csConditions) {
            csTenderMapper.updateCandidateByObj(candidate);
        }

        return csConditions.size();
    }

    private List<CsCandidate> recalculateRanking(List<CsCandidate> candidates) {
        // 根据分数和是否推荐等因素，重新计算排名
        candidates.sort(Comparator.comparing(CsCandidate::getFinalScore, Comparator.reverseOrder())
                .thenComparing(candidate -> !(candidate.getRecommend() == 0)));
        for (int i = 0; i < candidates.size(); i++) {
            candidates.get(i).setRanking(i + 1L);
        }
        return candidates;
    }

    @Override
    public List<File> getBidDocument(String iNumber) {
        List<File> files = new ArrayList<>();

        //能访问到这个一般是供应商
        LoginUser loginUser = SecurityUtils.getLoginUser();
        Long userid = loginUser.getUserid();
        //先判断供应商是否填写业务经办人信息
        //判断该项目是否是邀请招标,该供应商是否有被邀请
        CsTender tender = csTenderMapper.getTender(iNumber);
        Integer hId = csTenderMapper.UserRelationHid(userid);
        if (tender.getiWay() != 1) {
            Integer count = csTenderMapper.getInviteSupplier(iNumber, hId);
            if (count == null) {
                File file = new File();
                file.setName("没有资格");
                files.add(file);
                return files;
            }
        }
        Integer is = csTenderMapper.isExitoperator(hId);
        if (is <= 0) {
            File file = new File();
            file.setName("补充");
            files.add(file);
            return files;
        }

        Integer isEnd = csTenderMapper.isPublicyEndTime(iNumber);
        if (isEnd == 0) {
            return null;
        }
        Integer supplierExit = csTenderMapper.getSupplierExit(iNumber, Long.valueOf(hId));
        if (supplierExit > 0) {
            File file = new File();
            file.setName("已获得");
            files.add(file);
            return files;
        }
        CsGetTender csGetTender = new CsGetTender();
        csGetTender.sethId(hId);
        csGetTender.setiNumber(iNumber);
        csGetTender.setyDownLoadTime(new Date());
        //新增
        Integer integer = csTenderMapper.addCsGetTender(csGetTender);
        if (integer > 0) {
            return csTenderMapper.getTenderNotice(iNumber);
        }
        //返回招标公告的文件
        return null;
    }

    @Override
    public Integer addSubmission(CSSubmission csSubmission) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        Integer hId = csTenderMapper.UserRelationHid(loginUser.getUserid());
        Integer supplierExit = csTenderMapper.getSupplierExit(csSubmission.getiNumber(), hId.longValue());
        if (supplierExit == 0) {
            return 0;
        }
        csSubmission.setTdSuccessTime(new Date());
        csSubmission.setIpAddress(IpUtils.getIpAddr());
        csSubmission.setTdStatus(0);
        csSubmission.sethId(hId);
        return csTenderMapper.addSubmission(csSubmission);
    }

    @Override
    public Map<String, Object> getBidWinningCandidate(String iNumber) {
        //中标候选人
        CompletableFuture<CsApplications> uCompletableFuture = CompletableFuture.supplyAsync(() -> csTenderMapper.getCsApplications(iNumber));
        List<CsCandidate> bidWinningCandidateList = csTenderMapper.getBidWinningCandidate(iNumber);
        CsTender csTender = csTenderMapper.getTenderStartTime(iNumber);
        Map<String, Object> map = new HashMap<>();
        map.put("candidate", bidWinningCandidateList);
        map.put("csTender", csTender);
        try {
            map.put("csApplications", uCompletableFuture.get());
        } catch (InterruptedException | ExecutionException e) {
            throw new RuntimeException(e);
        }
        return map;
    }

    @Override
    public Integer setStartTenderTime(CsTender csTender) {
        CsTender tender = csTenderMapper.getTender(csTender.getiNumber());
        if (csTender.getpStartTime() == null) {
            return csTenderMapper.updateCsTender(csTender);
        }
        if (tender.getStartTime() != null) {
            csTenderMapper.updateCsTender(csTender);
            //说明这个是设置中标公示期的
            long time = csTender.getpEndTime().getTime();
            long l = time - new Date().getTime();
            try {
                String s = objectMapper.writeValueAsString(csTender);
                Random random = new Random();
                int fourDigitRandomNumber = random.nextInt(9000) + 1000;
                CorrelationData correlationData = new CorrelationData("4564" + fourDigitRandomNumber);
                rabbitTemplate.convertAndSend(RabbitMqConfig.COMPLETE_BINDING_EXCHANGE, RabbitMqConfig.COMPLETE_BINDING_ROUTE, s, msg -> {
                    msg.getMessageProperties().setHeader("x-delay", l);
                    msg.getMessageProperties().setContentType(MessageProperties.CONTENT_TYPE_JSON);
                    msg.getMessageProperties().setMessageId("4564" + fourDigitRandomNumber);
                    return msg;
                }, correlationData);
            } catch (JsonProcessingException e) {
                throw new RuntimeException(e);
            }
            return 1;
        }
        return 0;
    }

    /**
     * 通过中标公告结束时间确定项目完成
     */
    @RabbitListener(queues = RabbitMqConfig.COMPLETE_BINDING_QUEUE)
    public void completeTender(CsTender csTender, Message message, Channel channel) {
        System.out.println("csTender = " + csTender);
        String messageId = message.getMessageProperties().getMessageId();
        int retryCount = retryCountMap.getOrDefault(messageId, 0);
        if (retryCount >= MAX_RETRIES) {
            System.out.println("消息 " + messageId + " 达到最大重试次数 " + MAX_RETRIES + " 次，拒绝消息。");
            try {
                channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
            } catch (Exception e) {
                System.out.println("消息拒绝失败: " + e);
            }
            return;
        }
        retryCount++;
        retryCountMap.put(messageId, retryCount);
        try {
            CsTender newTender = new CsTender();
            newTender.setProjectState(8L);
            newTender.setiNumber(csTender.getiNumber());
            int i = csTenderMapper.updateCsTender(newTender);
            System.out.println("i = " + i);
            if (i > 0) {
                channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
            } else {
                channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
            }
        } catch (Exception e) {
            System.out.println("e = " + e);
        }
    }

    @Override
    public Integer confirmWinningBidder(List<CsCandidate> strings) {
        List<String> collect = strings.stream().map(CsCandidate::gethId).toList();
        return csTenderMapper.updateCandidate(collect, strings.get(0).getiNumber());
    }

    @Override
    public Map<String, Object> getBidWinningCandidateAndSended(String iNumber) {
        CompletableFuture<CsTender> csTenderCompletableFuture = CompletableFuture.supplyAsync(() -> csTenderMapper.getTender(iNumber));
        List<CsCandidate> bidWinningCandidateList = csTenderMapper.getBidWinningCandidateAndBid(iNumber);//已中标的(未分开的)
        List<WinningResultsSupplier> results = csTenderMapper.getSupplierSended(iNumber);
        Map<String, Object> map = new HashMap<>();
        map.put("bidWinningCandidateList", bidWinningCandidateList);
        map.put("results", results);
        List<CsCandidate> csCandidates = bidWinningCandidateList
                .stream()
                .filter(csCandidate -> results.contains(csCandidate.gethId()))
                .toList();
        map.put("csCandidates", csCandidates);
        try {
            map.put("csTender", csTenderCompletableFuture.get());
        } catch (InterruptedException | ExecutionException e) {
            throw new RuntimeException(e);
        }
        return map;
    }

    @Override
    public List<WinningResultsSupplier> setNoticeToSupplier(List<CsWinningResults> candidates) {
        Integer integer = csTenderMapper.setNoticeToSupplier(candidates);
        if (integer > 0) {
            return csTenderMapper.getSupplierSended(candidates.get(0).getiNumber());
        }
        return null;
    }

    @Override
    public int selectTenderCount() {
        return csTenderMapper.selectTenderCount();
    }

    @Override
    public List<CsTender> selectTenderByState(CsTender csTender) {
        return csTenderMapper.selectTenderByState(csTender);
    }

    @Override
    public int selectTenderByStateCount(CsTender csTender) {
        return csTenderMapper.selectTenderByStateCount(csTender);
    }

    @Override
    public TenderStatusTime getTenderStatusTime(String iNumber) {
        return csTenderMapper.getTenderStatusTime(iNumber);
    }

    @Override
    public List<CsWinningResults> getBidingResult() {
        Long userid = SecurityUtils.getLoginUser().getUserid();
        CsSupplier csSupplier = csTenderMapper.getSupplierIdByUid(userid);
        if (csSupplier != null) {
            return csTenderMapper.getBidingResult(csSupplier.getHid());
        }
        return null;
    }

    @Override
    public CsSupplier getPersonInfo() {
        Long userid = SecurityUtils.getLoginUser().getUserid();
        CsSupplier csSupplier = csTenderMapper.getSupplierIdByUid(userid);
        if (csSupplier != null) {
            return csTenderMapper.getPersonInfo(csSupplier.getHid());
        }
        return null;
    }

    @Override
    public Map<String, Object> getLoginTenderInfo() {
        List<TenderNoticeVO> todayList = csTenderMapper.getTodayTender();
        List<CsTender> csTenders = csTenderMapper.getAllTender();
        List<CsWinningResults> bidTenderList = csTenderMapper.getBidingResultByStatus();//中标

        Map<String, Object> map = new HashMap<>();
        map.put("todayList", todayList);
        map.put("csTenders", csTenders);
        map.put("bidTenderList", bidTenderList);
        return map;
    }

    @Override
    public TenderNoticeVO getTenderNoticeInfo(String iNumber) {
        return csTenderMapper.getTenderNoticeInfo(iNumber);
    }

    @Override
    public List<CsCandidate> getWinnResult(String iNumber) {
        return csTenderMapper.getWinnResult(iNumber);
    }

    @Override
    public List<CsCandidate> getNoBidingResult() {
        Long userid = SecurityUtils.getLoginUser().getUserid();
        CsSupplier csSupplier = csTenderMapper.getSupplierIdByUid(userid);
        if (csSupplier != null) {
            return csTenderMapper.getNoBidingResult(csSupplier.getHid());
        }
        return null;
    }

    @Override
    public List<CSCategory> getCategory() {
        return csTenderMapper.getCategory();
    }
}
